package elephant.servers.consoleserver;

import java.io.File;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;

import org.apache.sshd.server.SshServer;
import org.apache.sshd.server.auth.password.PasswordAuthenticator;
import org.apache.sshd.server.auth.password.PasswordChangeRequiredException;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
import org.apache.sshd.server.session.ServerSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import elephant.Container;
import elephant.Server;
import elephant.servers.consoleserver.command.SshdCommand;
import elephant.servers.consoleserver.termos.CliRunnerCommandFactory;
import elephant.util.ObjectPrinter;

/**
 * 
 * @author icecooly
 *
 */
public class ConsoleServer implements Server{
	//
	private static final Logger logger=LoggerFactory.getLogger(ConsoleServer.class);
	//
	private SshServer sshServer;
	private int port=9999;
	private Map<String,String> userMap;
	private CliRunnerCommandFactory factory;
	//
	public ConsoleServer(){
		userMap=new HashMap<>();
		userMap.put("root", "ConsoleServe890*()");//default
	}
	
	@Override
	public void init() throws Exception {
		logger.info("init");
		sshServer=SshServer.setUpDefaultServer();
		sshServer.setPort(port);
		String filePath="hostkey.ser";
		if(Container.get().getServerPath()!=null){
			filePath=Container.get().getServerPath()+File.separator+"hostkey.ser";
		}
		SimpleGeneratorHostKeyProvider hostKeyProvider=new SimpleGeneratorHostKeyProvider(new File(filePath));
		hostKeyProvider.setAlgorithm("RSA");//defualt is DSA
		sshServer.setKeyPairProvider(hostKeyProvider);
		sshServer.setPasswordAuthenticator(new PasswordAuthenticator() {
			@Override
			public boolean authenticate(String username, String pwd, ServerSession session) 
			throws PasswordChangeRequiredException {
				InetSocketAddress address=(InetSocketAddress)session.getIoSession().getRemoteAddress();
				boolean authRet=true;
				String password=userMap.get(username);
				if(password==null||username==null||pwd==null||(!password.equals(pwd))){
					authRet=false;
				}
				logger.info("authenticate username:{} pwd:{} host:{} port:{} result:{}",
						username,pwd,address.getHostString(),address.getPort(),authRet);
				return authRet;
			}
		});
		//
		factory=new CliRunnerCommandFactory();
		sshServer.setShellFactory(factory);
		String banner="\n"+("Welcome to Elephant")+"\n"+
				"type 'help' for more information.\n";
		sshServer.getProperties().put(SshServer.WELCOME_BANNER, banner);
	}
	
	@Override
	public void start() throws Exception {
		logger.info("start");
		sshServer.start();	
	}
	
	@Override
	public void stop() throws Exception {
		logger.info("stop");
		sshServer.stop();
	}

	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}

	public void addUser(String userName,String password){
		userMap.put(userName, password);
	}
	
	public void removeUser(String userName){
		userMap.remove(userName);
	}
	
	public void registerCommand(SshdCommand cmd){
		factory.registerCommand(cmd);
	}
	
	@Override
	public String dump() {
		ObjectPrinter op=new ObjectPrinter();
		op.section(this.getClass().getSimpleName());
		op.print("port",port);
		op.secondSection("users");
		userMap.forEach((k,v)->{
			op.print(k,v);
		});
		op.secondSection("commands");
		factory.commands.forEach((k,v)->{
			op.print(k,v);
		});
		return op.toString();
	}
	//
	public static void main(String[] args) throws Exception {
		ConsoleServer consoleServer=new ConsoleServer();
		consoleServer.init();
		consoleServer.start();
		Thread.sleep(500000);
	}
}
